﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Zore.App.Shared.Helpers
{
    public static class EnumHelper
    {
        /// <summary>
        /// 判断是否为可空枚举
        /// </summary>
        public static bool IsNullableEnum(this Type type)
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                var underlyingType = Nullable.GetUnderlyingType(type);
                return underlyingType != null && underlyingType.IsEnum;
            }
            return false;
        }

        /// <summary>
        /// 根据Description属性的值来获取可空枚举值
        /// </summary>
        public static TEnum? GetNullableEnumValueFromDescription<TEnum>(this string description) where TEnum : struct, Enum
        {
            var type = typeof(TEnum);
            if (type.IsEnum)
            {
                foreach (var field in type.GetFields())
                {
                    if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))
                        is DescriptionAttribute attribute && attribute.Description == description)
                    {
                        return (TEnum)field.GetValue(null);
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 根据Description属性的值来获取枚举值
        /// </summary>
        public static TEnum GetEnumValueFromDescription<TEnum>(this string description)
        {
            var type = typeof(TEnum);
            if (!type.IsEnum)
            {
                throw new ArgumentException("T must be an enumerated type");
            }

            foreach (var field in type.GetFields())
            {
                var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (attribute != null && attribute.Description == description)
                {
                    return (TEnum)field.GetValue(null);
                }
            }

            throw new ArgumentException($"Enum value with description '{description}' not found in type {type.Name}");
        }

        /// <summary>
        /// 从字符串中获取指定类型的枚举值
        /// </summary>
        public static TEnum ParseEnum<TEnum>(this string value) where TEnum : struct
        {
            if (Enum.TryParse(value, out TEnum result))
            {
                return result;
            }
            else
            {
                throw new Exception($"The value '{value}' is not a valid enum value of type '{typeof(TEnum).FullName}'.");
            }
        }

        /// <summary>
        /// 获取枚举类型的所有值数组
        /// </summary>
        public static TEnum[] GetValues<TEnum>() where TEnum : struct, Enum
        {
            return Enum.GetValues(typeof(TEnum)) as TEnum[];
        }

        /// <summary>
        /// 获取枚举类型的名称数组
        /// </summary>
        public static string[] GetNames<TEnum>() where TEnum : struct, Enum
        {
            return Enum.GetNames(typeof(TEnum));
        }

        /// <summary>
        /// 判断指定值是否为枚举类型的有效值
        /// </summary>
        public static bool IsValidValue<TEnum>(TEnum value) where TEnum : struct, Enum
        {
            return Enum.IsDefined(typeof(TEnum), value);
        }

        /// <summary>
        /// 获取枚举类型中包含的值的数量
        /// </summary>
        public static int Count<TEnum>() where TEnum : struct, Enum
        {
            return Enum.GetValues(typeof(TEnum)).Length;
        }

        /// <summary>
        /// 获取枚举值的Description特性
        /// </summary>
        public static string GetDescription(this Enum value)
        {
            if (value == null) return string.Empty;

            FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
            DescriptionAttribute[] attributes = fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];

            if (attributes != null && attributes.Length > 0)
            {
                return attributes[0].Description;
            }
            else
            {
                return value.ToString();
            }
        }

        /// <summary>
        /// 获取枚举类型的所有键值对列表
        /// </summary>
        public static Dictionary<int, string> GetKeyValueList<TEnum>() where TEnum : struct, Enum
        {
            return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().ToDictionary(x => Convert.ToInt32(x), x => x.GetDescription());
        }

        /// <summary>
        /// 获取枚举类型的所有键值对列表
        /// </summary>
        public static List<(TEnum, string)> GetList<TEnum>() where TEnum : struct, Enum
        {
            return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Select(x => (x, x.GetDescription())).ToList();
        }

        /// <summary>
        /// 判断一个枚举值是否包含指定的枚举常量。
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <param name="value">要检查的枚举值</param>
        /// <param name="flag">要检查的枚举常量</param>
        /// <returns>如果枚举值包含指定的枚举常量，则为 true；否则为 false。</returns>
        public static bool HasFlag<TEnum>(this TEnum value, TEnum flag) where TEnum : struct, Enum
        {
            if (!typeof(TEnum).IsEnum)
            {
                throw new Exception($"{nameof(TEnum)} must be an enumerated type.");
            }

            var valueLong = Convert.ToInt64(value);
            var flagLong = Convert.ToInt64(flag);

            return (valueLong & flagLong) == flagLong;
        }

        /// <summary>
        /// 将一个枚举值拆分为其包含的单个枚举常量。
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <param name="value">要拆分的枚举值</param>
        /// <returns>枚举常量数组</returns>
        public static TEnum[] GetFlags<TEnum>(this TEnum value) where TEnum : struct, Enum
        {
            if (!typeof(TEnum).IsEnum)
            {
                throw new Exception($"{nameof(TEnum)} must be an enumerated type.");
            }

            var values = Enum.GetValues(typeof(TEnum));
            var result = new List<TEnum>();

            foreach (TEnum val in values)
            {
                if (value.HasFlag(val))
                {
                    result.Add(val);
                }
            }

            return result.ToArray();
        }

        /// <summary>
        /// 将多个枚举值合并为一个枚举值。
        /// </summary>
        /// <typeparam name="TEnum">枚举类型</typeparam>
        /// <param name="flags">要合并的枚举值数组</param>
        /// <returns>合并后的枚举值</returns>
        public static TEnum MergeFlags<TEnum>(params TEnum[] flags)
            where TEnum : struct, Enum
        {
            if (!typeof(TEnum).IsEnum)
            {
                throw new Exception($"{nameof(TEnum)} must be an enumerated type.");
            }

            var result = default(TEnum);
            var underlyingType = Enum.GetUnderlyingType(typeof(TEnum));

            foreach (var flag in flags)
            {
                if (flag.Equals(default(TEnum)))
                {
                    continue;
                }

                var convertedFlag = Convert.ChangeType(flag, underlyingType);

                result = (TEnum)Enum.ToObject(typeof(TEnum), Convert.ToUInt64(result) | Convert.ToUInt64(convertedFlag));
            }

            return result;
        }
    }
}
